import md5 from 'js-md5' //引入MD5加密
import UpApi from '@/api/common.js'
import {
	concurrentExecution
} from '@/utils/jnxh'

/**
 * 文件分片上传
 * @params file {File} 文件
 * @params pieceSize {Number} 分片大小 默认3MB
 * @params concurrent {Number} 并发数量 默认2
 * @params process {Function} 进度回调函数
 * @params success {Function} 成功回调函数
 * @params error {Function} 失败回调函数
 */
export const uploadByPieces = ({
	file,
	pieceSize = 3,
	concurrent = 3,
	success,
	process,
	error
}) => {
	// 如果文件传入为空直接 return 返回
	if (!file || file.length < 1) {
		return error('文件不能为空')
	}
	let fileMD5 = '' // 总文件列表
	const chunkSize = pieceSize * 1024 * 1024 // 1MB一片
	const chunkCount = Math.ceil(file.size / chunkSize) // 总片数
	const chunkList = [] // 分片列表
	let uploaded = [] // 已经上传的
	let fileType = '' // 文件类型
	// 获取md5
	/***
	 * 获取md5
	 **/
	const readFileMD5 = () => {
		// 读取视频文件的md5
		fileType = file.name.substring(file.name.lastIndexOf('.') + 1, file.name.length)
		console.log('获取文件的MD5值')
		let fileRederInstance = new FileReader()
		console.log('file', file)
		fileRederInstance.readAsBinaryString(file)
		fileRederInstance.addEventListener('load', e => {
			let fileBolb = e.target.result
			fileMD5 = md5(fileBolb)
			var index = file.name.lastIndexOf('.')
			var tp = file.name.substring(index + 1, file.name.length)
			let form = new FormData()
			form.append('filename', file.name)
			form.append('identifier', fileMD5)
			form.append('objectType', fileType)
			form.append('chunkNumber', 1)
			UpApi.uploadChunk(form).then(res => {
				if (res.skipUpload) {
					console.log('文件已被上传')
					success && success(res)
				} else {
					// 判断是否是断点续传
					if (res.uploaded && res.uploaded.length != 0) {
						uploaded = [].concat(res.uploaded)
					}
					console.log('已上传的分片：' + uploaded)
					// 判断是并发上传或顺序上传
					if (concurrent == 1 || chunkCount == 1) {
						console.log('顺序上传')
						sequentialUplode(0)
					} else {
						console.log('并发上传')
						concurrentUpload()
					}
				}
			}).catch((e) => {
				console.log('文件合并错误')
				console.log(e)
			})
		})
	}
	/***
	 * 获取每一个分片的详情
	 **/
	const getChunkInfo = (file, currentChunk, chunkSize) => {
		let start = currentChunk * chunkSize
		let end = Math.min(file.size, start + chunkSize)
		let chunk = file.slice(start, end)
		return {
			start,
			end,
			chunk
		}
	}
	/***
	 * 针对每个文件进行chunk处理
	 **/
	const readChunkMD5 = () => {
		// 针对单个文件进行chunk上传
		for (var i = 0; i < chunkCount; i++) {
			const {
				chunk
			} = getChunkInfo(file, i, chunkSize)

			// 判断已经上传的分片中是否包含当前分片
			if (uploaded.indexOf(i + '') == -1) {
				uploadChunk({
					chunk,
					currentChunk: i,
					chunkCount
				})
			}
		}
	}
	/***
	 * 原始上传
	 **/
	const uploadChunk = (chunkInfo) => {
		var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
		console.log(sd, '进度')
		process(sd)
		console.log(chunkInfo, '分片大小')
		let inde = chunkInfo.currentChunk + 1
		if (uploaded.indexOf(inde + '') > -1) {
			const {
				chunk
			} = getChunkInfo(file, chunkInfo.currentChunk + 1, chunkSize)
			uploadChunk({
				chunk,
				currentChunk: inde,
				chunkCount
			})
		} else {
			var index = file.name.lastIndexOf('.')
			var tp = file.name.substring(index + 1, file.name.length)
			// 构建上传文件的formData
			let fetchForm = new FormData()
			fetchForm.append('identifier', fileMD5)
			fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)
			fetchForm.append('chunkSize', chunkSize)
			fetchForm.append('currentChunkSize', chunkInfo.chunk.size)
			const chunkfile = new File([chunkInfo.chunk], file.name)
			fetchForm.append('file', chunkfile)
			// fetchForm.append('file', chunkInfo.chunk)
			fetchForm.append('filename', file.name)
			fetchForm.append('relativePath', file.name)
			fetchForm.append('totalChunks', chunkInfo.chunkCount)
			fetchForm.append('totalSize', file.size)
			fetchForm.append('objectType', tp)
			// 执行分片上传
			let config = {
				headers: {
					'Content-Type': 'application/json',
					'Accept': '*/*'
				}
			}

			UpApi.uploadChunk(fetchForm, config).then(res => {

				if (res.code == 200) {
					console.log('分片上传成功')
					uploaded.push(chunkInfo.currentChunk + 1)
					// 判断是否全部上传完
					if (uploaded.length == chunkInfo.chunkCount) {
						console.log('全部完成')
						success(res)
						process(100)
					} else {
						const {
							chunk
						} = getChunkInfo(file, chunkInfo.currentChunk + 1, chunkSize)
						uploadChunk({
							chunk,
							currentChunk: chunkInfo.currentChunk + 1,
							chunkCount
						})
					}

				} else {
					console.log(res.msg)
				}

			}).catch((e) => {
				error && error(e)
			})
			// if (chunkInfo.currentChunk < chunkInfo.chunkCount) {
			//   setTimeout(() => {
			//
			//   }, 1000)
			// }
		}
	}
	/***
	 * 顺序上传
	 **/
	const sequentialUplode = (currentChunk) => {
		const {
			chunk
		} = getChunkInfo(file, currentChunk, chunkSize)
		let chunkInfo = {
			chunk,
			currentChunk,
			chunkCount
		}
		var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
		process(sd)
		console.log('当前上传分片：' + currentChunk)
		let inde = chunkInfo.currentChunk + 1
		if (uploaded.indexOf(inde + '') > -1) {
			console.log('分片【' + currentChunk + '】已上传')
			sequentialUplode(currentChunk + 1)
		} else {
			let uploadData = createUploadData(chunkInfo)
			let config = {
				headers: {
					'Content-Type': 'application/json',
					'Accept': '*/*'
				}
			}
			// 执行分片上传
			UpApi.uploadChunk(uploadData, config).then(res => {
				if (res.code == 200) {
					console.log('分片【' + currentChunk + '】上传成功')
					uploaded.push(chunkInfo.currentChunk + 1)
					// 判断是否全部上传完
					if (uploaded.length == chunkInfo.chunkCount) {
						console.log('全部完成')
						success(res)
						process(100)
					} else {
						sequentialUplode(currentChunk + 1)
					}

				} else {
					console.log(res.msg)
				}

			}).catch((e) => {
				error && error(e)
			})
		}
	}
	/***
	 * 并发上传
	 **/
	const concurrentUpload = () => {
		for (var i = 0; i < chunkCount; i++) {
			chunkList.push(Number(i))
		}
		console.log('需要上传的分片列表：' + chunkList)
		concurrentExecution(chunkList, concurrent, (curItem) => {
			return new Promise((resolve, reject) => {
				const {
					chunk
				} = getChunkInfo(file, curItem, chunkSize)
				let chunkInfo = {
					chunk,
					currentChunk: curItem,
					chunkCount
				}
				var sd = parseInt((chunkInfo.currentChunk / chunkInfo.chunkCount) * 100)
				process(sd)
				console.log('当前上传分片：' + curItem)
				let inde = chunkInfo.currentChunk + 1
				if (uploaded.indexOf(inde + '') == -1) {
					// 构建上传文件的formData
					let uploadData = createUploadData(chunkInfo)
					// 请求头
					let config = {
						headers: {
							'Content-Type': 'application/json',
							'Accept': '*/*'
						}
					}
					UpApi.uploadChunk(uploadData, config).then(res => {
						if (res.code == 200) {
							uploaded.push(chunkInfo.currentChunk + 1)
							console.log('已经上传完成的分片：' + uploaded)
							// 判断是否全部上传完
							if (uploaded.length == chunkInfo.chunkCount) {
								success(res)
								process(100)
							}
							resolve()
						} else {
							reject(res)
							console.log(res.msg)
						}

					}).catch((e) => {
						reject(res)
						error && error(e)
					})
				} else {
					console.log('分片【' + chunkInfo.currentChunk + '】已上传')
					resolve()
				}
			})
		}).then(res => {
			console.log('finish', res)
		})
	}
	/***
	 * 创建文件上传参数
	 **/
	const createUploadData = (chunkInfo) => {
		let fetchForm = new FormData()
		fetchForm.append('identifier', fileMD5)
		fetchForm.append('chunkNumber', chunkInfo.currentChunk + 1)
		fetchForm.append('chunkSize', chunkSize)
		fetchForm.append('currentChunkSize', chunkInfo.chunk.size)
		const chunkfile = new File([chunkInfo.chunk], file.name)
		fetchForm.append('file', chunkfile)
		// fetchForm.append('file', chunkInfo.chunk)
		fetchForm.append('filename', file.name)
		fetchForm.append('relativePath', file.name)
		fetchForm.append('totalChunks', chunkInfo.chunkCount)
		fetchForm.append('totalSize', file.size)
		fetchForm.append('objectType', fileType)
		return fetchForm
	}
	readFileMD5() // 开始执行代码
}
